/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package br.ufrj.dcc.pushpeer.observers;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import peersim.config.Configuration;
import peersim.core.Control;
import peersim.core.Network;
import peersim.util.IncrementalFreq;
import br.ufrj.dcc.pushpeer.protocol.PushPeer;

public class SeedersObserver implements Control{

	/**
	 *	Whether to output for gnuplot or not.
	 */
	private static final boolean GNUPLOT_OUT = true;
	
	/**
	 *	The protocol to operate on.
	 */
	private static final String PAR_PROT="protocol";
	
	/**
	 * The number of files being simulated.
	 */
	private static final String NUM_FILES="num_files";
	
	/**
	 *	Protocol identifier, obtained from config property.
	 */
	private final int pid;
	
	/**
	 * Number of files being simulated.
	 */
	private int numFiles;
	
	/**
	 * Used for gnuplot output printing.
	 */
	private File file;
	
	/**
	 * Used for gnuplot output printing.
	 */
	private FileWriter writer;
	
	/**
	 *	The basic constructor that reads the configuration file.
	 *	@param prefix The configuration prefix for this class.
	 */
	public SeedersObserver(String prefix) {
		pid = Configuration.getPid(prefix + "." + PAR_PROT);
		
		numFiles = Configuration.getInt(prefix + "." + NUM_FILES);
		
		if(GNUPLOT_OUT) {
			file = new File("graphs\\gnuplot_output_s.dat");
			writer = null;
			try {
				writer = new FileWriter(file);
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				writer.write("##");
				for(int i=1; i<=numFiles; i++) {
					writer.write("f" + i + "_seeders ");
				}
				writer.write("\r\n");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Prints information about the PushPeer network
	 * and the number of leechers and seeders.
	 * @return Always false.
	 */
	public boolean execute() {
		
		List<IncrementalFreq> nodeStatusStats = new ArrayList<IncrementalFreq>(numFiles);
		for(int i=1; i <= numFiles; i++){
			nodeStatusStats.add(new IncrementalFreq());
		}
		
		//IncrementalStats neighborStats = new IncrementalStats();
		
		int numberOfNodes = Network.size();
		//int numberOfCompletedPieces = 0;
		
		for(int i=1; i <= numFiles; i++){
			for(int j=0; j < numberOfNodes; j++) {
				//Stats on the number of seeders for every file.
				if(((PushPeer)(Network.get(j).getProtocol(pid))).getPeerStatus(i) == PushPeer.SEEDER)
					nodeStatusStats.get(i-1).add(PushPeer.SEEDER);
			}
			
			//Stats on number of neighbors per peer.
			//neighborStats.add(((PushPeer)(Network.get(i).getProtocol(pid))).getNNodes());
		}
		
		//Probably not needed... I don't care for individual peer's stats
		/*
		
		// number of the pieces of the file, equal for every node, here 1 is chosen,
		// since 1 is the first "normal" node (0 is the tracker)
		int numberOfPieces = ((PushPeer)(Network.get(1).getProtocol(pid))).getNPieces();
		
		for (int i=1; i<numberOfNodes; ++i) {
			numberOfCompletedPieces = 0;
			
			// discovers the status of the current peer (leecher or seeder)
			//int ps = ((PushPeer)(Network.get(i).getProtocol(pid))).getPeerStatus();
			String peerStatus;
			if (ps==0) {
				peerStatus = "L"; //leecher
			}
			else {
				peerStatus = "S"; //seeder
			}
			
			
			if (Network.get(i)!=null) {
				
				// counts the number of completed pieces for the i-th node
				for (int j=0; j<numberOfPieces; j++) {
					/*if ( ((PushPeer)(Network.get(i).getProtocol(pid))).getFileStatus()[j] == 16) {
						numberOfCompletedPieces++;
					}* /
				}
				
				
				 /*Put here the output lines of the Observer. An example is provided with
				 basic information and stats.
				 CommonState.getTime() is used to print out time references
				 (useful for graph plotting).* /
				 
				
				//System.out.println("OBS: node " + ((PushPeer)(Network.get(i).getProtocol(pid))).getThisNodeID() + "(" + peerStatus + ")" + "\t pieces completed: " + numberOfCompletedPieces + "\t \t down: " + ((PushPeer)(Network.get(i).getProtocol(pid))).nPiecesDown + "\t up: " + ((PushPeer)(Network.get(i).getProtocol(pid))).nPiecesUp + " time: " + CommonState.getTime());
				//System.out.println("[OBS] t " + CommonState.getTime() + "\t pc " + numberOfCompletedPieces + "\t n " + ((BitTorrent)(Network.get(i).getProtocol(pid))).getThisNodeID());
			}
			else {
				//System.out.println("[OBS] t " + CommonState.getTime() + "\t pc " + "0" + "\t n " + "0");
			}
		
		}*/
		
		// prints the frequency of 0 (leechers) and 1 (seeders)
		if(GNUPLOT_OUT) {
			try {
				writer.write("##" + peersim.core.CommonState.getTime() + " \r\n");
				for(int i=0; i<numFiles; i++){
					writer.write(nodeStatusStats.get(i).getFreq(PushPeer.SEEDER) + "\r\n");
					//System.out.print(nodeStatusStats.get(i).toString().replace(") (" + Integer.toString(PushPeer.LEECHER) + ",", " ").replace(") (" + Integer.toString(PushPeer.SEEDER) + ",", " ").replace(") (" + Integer.toString(PushPeer.NOT_INTERESTED) + ",", " "));
				}
				writer.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		else {
			for(int i=0; i<numFiles; i++){
				System.out.println("File " + (i+1) + ": ");
				System.out.println(nodeStatusStats.get(i).toString().replace(Integer.toString(PushPeer.SEEDER) + ",", "Seeders: "));
			}
			System.out.println("");
		}
		
		// prints the average number of neighbors per peer
		//System.out.println("Avg. number of neighbors per peer: " + neighborStats.getAverage());
		
		return false;
	}
}
